package com.logic.landseaserver.service.impl;


import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.logic.common.exception.BusinessException;
import com.logic.common.security.SecurityUtils;
import com.logic.common.util.QueryUtil;
import com.logic.common.util.SysUtil;
import com.logic.landseaserver.common.LandeaConstants;
import com.logic.landseaserver.common.LandeaConstants.ProduceType;
import com.logic.landseaserver.common.enums.BillStatusEnum;
import com.logic.landseaserver.common.enums.BillTypeEnum;
import com.logic.landseaserver.common.util.ConstantChar;
import com.logic.landseaserver.common.util.DateUtil;
import com.logic.landseaserver.common.util.LandSeaUtil;
import com.logic.landseaserver.common.util.StringTools;
import com.logic.landseaserver.domain.BalanceSheetRecord;
import com.logic.landseaserver.domain.Contract;
import com.logic.landseaserver.domain.MonthlyBill;
import com.logic.landseaserver.domain.MonthlyBillBalanceRecord;
import com.logic.landseaserver.domain.PreOffrentBill;
import com.logic.landseaserver.persistence.read.BillReadMapper;
import com.logic.landseaserver.persistence.read.CheckFeeListReadMapper;
import com.logic.landseaserver.persistence.read.ContractReadMapper;
import com.logic.landseaserver.persistence.read.MeterDataReadMapper;
import com.logic.landseaserver.persistence.read.MonthlyBillReadMapper;
import com.logic.landseaserver.persistence.read.PreOffrentBillReadMapper;
import com.logic.landseaserver.persistence.write.MonthlyBillWriteMapper;
import com.logic.landseaserver.service.IMonthlyBillService;
import com.logic.landseaserver.ws.dto.CheckFeeListDTO;
import com.logic.landseaserver.ws.dto.ContractMonthFeeDTO;
import com.logic.landseaserver.ws.dto.MeterConsumptionDataDTO;
import com.logic.landseaserver.ws.dto.MonthlyBillDTO;

@Service
public class MonthlyBillServiceImpl implements IMonthlyBillService {

    @Autowired
    private MonthlyBillReadMapper monthlyBillReadMapper;

    @Autowired
    private MonthlyBillWriteMapper monthlyBillWriteMapper;

    @Autowired
    private MeterDataReadMapper meterDataReadMapper;

    @Autowired
    private ContractReadMapper contractReadMapper;

    @Autowired
    private CheckFeeListReadMapper checkFeeListReadMapper;
    
    @Autowired
    private BillReadMapper billReadMapper;
    
    @Autowired
    private PreOffrentBillReadMapper preOffrentBillReadMapper;

    @Override
    public void delete(String arg0) throws BusinessException {
        String[] idArr = arg0.split(",");
        for (String id : idArr) {
            Integer monthlyBillId = Integer.valueOf(id);
            MonthlyBill monthlyBill = (MonthlyBill) this.get(monthlyBillId);
            Boolean pass = this.validateForDelete(monthlyBill);
            if (pass) {
                monthlyBill.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
                monthlyBillWriteMapper.deleteByPrimaryKey(monthlyBill);
            }
        }

    }

    @Override
    public Object get(Integer arg0) throws BusinessException {
        return monthlyBillReadMapper.selectByPrimaryKey(arg0);
    }

    @Override
    public int insert(Object arg0) throws BusinessException {
        Integer id = -1;
        Boolean pass = this.validateForInsert(arg0);
        if (pass) {
            MonthlyBill monthlyBill = (MonthlyBill) arg0;
            setDefaultValue(monthlyBill);
            monthlyBill.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
            monthlyBillWriteMapper.insertSelective(monthlyBill);
            id = monthlyBill.getId();
        }
        return id;
    }

    private void setDefaultValue(MonthlyBill monthlyBill) {
        String dateString = SysUtil.convertDateToString(new Date(), "yyyyMM");
        monthlyBill.setBillMonth(dateString);
        monthlyBill.setStatus(BillStatusEnum.BIST3.getCode());//not pay
        Contract contract = contractReadMapper.selectByPrimaryKey(monthlyBill.getContractId());
        Integer roomId = contract.getRoomId();
        monthlyBill.setRoomId(roomId);
/*		String contractNo = contract.getContractNo();
        String billNo = contractNo + new DecimalFormat("00").format(monthlyBillReadMapper.getMaxBillNo());
		monthlyBill.setBillNo(billNo);*/
    }

    @Override
    public List<?> query(QueryUtil arg0) {
        return monthlyBillReadMapper.getList(arg0);
    }

    @Override
    public void update(Object arg0) throws BusinessException {
        Boolean pass = this.validateForUpdate(arg0);
        if (pass) {
            MonthlyBill monthlyBill = (MonthlyBill) arg0;
            monthlyBill.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
            monthlyBill.setCreatedBy(null);
            monthlyBill.setCreatedDtm(null);
            monthlyBillWriteMapper.updateByPrimaryKeySelective(monthlyBill);
        }

    }

    @Override
    public Boolean validate(Object arg0) throws BusinessException {
        Boolean pass = true;
        return pass;
    }

    @Override
    public Boolean validateForDelete(Object arg0) throws BusinessException {
        return true;
    }

    @Override
    public Boolean validateForInsert(Object arg0) throws BusinessException {
        Boolean pass = false;
        pass = this.validate(arg0);
        return pass;
    }

    @Override
    public Boolean validateForUpdate(Object arg0) throws BusinessException {
        Boolean pass = false;
        pass = this.validate(arg0);
        return pass;
    }


    /**
     * 
     * [描述]：合同其他费项查询月结费项</br>
     *
     * @param queryUtil
     * @return
     * @throws ParseException 
     *
     */
    @Override
    public List<MonthlyBillDTO> queryDTO(QueryUtil queryUtil) throws Exception 
    {
        List<MonthlyBillDTO> resultList = new ArrayList<MonthlyBillDTO>();
        
        // 是否需要查询出勾销记录,只有其他费项才需要显示(支付、未支付都需要显示)
        Map<String, Object> reqParamMap = queryUtil.getParams();
        String needShowCancelBill = StringTools.getString(reqParamMap.get("needShowCancelBill"));
        String contractId = StringTools.getString(reqParamMap.get("contractId"));
        String billStatus = StringTools.getString(reqParamMap.get("billStatus"));
        if (LandeaConstants.NEED_SHOW_CANCELBILL.equals(needShowCancelBill))
        {
            // 查询出所有的记录，包括被删除的
            List<MonthlyBillBalanceRecord> list = monthlyBillReadMapper.getDTOListWithBillCancel(queryUtil);
            if (CollectionUtils.isEmpty(list))
            {
                return resultList;
            }
            
            Map<String,List<Integer>> balanceIdMap = getMaxBalanceIdMap(list);
            
            for (MonthlyBillBalanceRecord monthlyBillBalanceRecord : list)
            {
                // 先判断是否被删除了
                if (monthlyBillBalanceRecord.getDeleted())
                {
                    // 不允许勾销
                    monthlyBillBalanceRecord.setId(null);
                    
                    // 从balance创建
                    MonthlyBillDTO monthlyBillDTO  =  monthlyBillBalanceRecord.buildMonthBillDTOFromBalance();
                    monthlyBillDTO.setCreatedDtm(monthlyBillBalanceRecord.getCreatedDtm());
                    resultList.add(monthlyBillDTO);
                    continue;
                }
                
                // 如果balance不存在
                if (null == monthlyBillBalanceRecord.getBsId())
                {
                    // 从monthBill创建
                    MonthlyBillDTO monthlyBillDTO  =  monthlyBillBalanceRecord.buildMonthBill();
                    monthlyBillDTO.setCreatedDtm(monthlyBillBalanceRecord.getCreatedDtm());
                    resultList.add(monthlyBillDTO);
                    continue;
                }
                
                String bsBillStatus = monthlyBillBalanceRecord.getBsBillStatus();
                Integer bsProduceType = monthlyBillBalanceRecord.getBsProduceType();
                // 未支付+支付类型
                if (BillStatusEnum.BIST3.getCode().equals(bsBillStatus) && ProduceType.PAY == bsProduceType.intValue())
                {
                    // 判断balanceId是否为最大,如果是，则realId保留，允许勾销
                    if (!isMaxId(balanceIdMap.get(String.valueOf(monthlyBillBalanceRecord.getId())), monthlyBillBalanceRecord.getBsId()))
                    {
                        // 不允许勾销
                        monthlyBillBalanceRecord.setId(null);
                        // 从balance创建
                        MonthlyBillDTO monthlyBillDTO  =  monthlyBillBalanceRecord.buildMonthBillDTOFromBalance();
                        monthlyBillDTO.setCreatedDtm(monthlyBillBalanceRecord.getCreatedDtm());
                        resultList.add(monthlyBillDTO);
                    }
                    else
                    {
                        // 从monthBill创建
                        MonthlyBillDTO monthlyBillDTO  =  monthlyBillBalanceRecord.buildMonthBill();
                        monthlyBillDTO.setCreatedDtm(monthlyBillBalanceRecord.getCreatedDtm());
                        resultList.add(monthlyBillDTO);
                    }
                    continue;
                }
                
                // 不允许勾销
                monthlyBillBalanceRecord.setId(null);
                
                // 从balance创建
                MonthlyBillDTO monthlyBillDTO  =  monthlyBillBalanceRecord.buildMonthBillDTOFromBalance();
                monthlyBillDTO.setCreatedDtm(monthlyBillBalanceRecord.getCreatedDtm());
                resultList.add(monthlyBillDTO);
                
            }
            
            // 如果已生成退租账单，则不让勾销
            PreOffrentBill preOffrentBill = preOffrentBillReadMapper.queryByContractId(Integer.parseInt(contractId));
            if (null != preOffrentBill)
            {
                for (MonthlyBillDTO monthBill : resultList)
                {
                    monthBill.setId(null);
                }
            }
            return resultList;
        }
        
        // 查询出所有，删除态时可能被勾销成0造成的，要具体判断是否要查询出
        List<MonthlyBillDTO> monthlyBillList = monthlyBillReadMapper.getDTOList(queryUtil);
        
        if (CollectionUtils.isEmpty(monthlyBillList))
        {
            return resultList;
        }
        
        return monthlyBillList;
    }
    
    @Override
    public List<MonthlyBillDTO> queryDTOWithNoCancel(QueryUtil queryUtil) throws Exception 
    {
        // 是否需要查询出勾销记录,只有其他费项才需要显示(支付、未支付都需要显示)
        Map<String, Object> reqParamMap = queryUtil.getParams();
        String needShowCancelBill = StringTools.getString(reqParamMap.get("needShowCancelBill"));
        String contractId = StringTools.getString(reqParamMap.get("contractId"));
        String billStatus = StringTools.getString(reqParamMap.get("billStatus"));
        if (LandeaConstants.NEED_SHOW_CANCELBILL.equals(needShowCancelBill))
        {
            List<MonthlyBillDTO> monthlyBillList = monthlyBillReadMapper.getDTOList(queryUtil);
            
            if (CollectionUtils.isEmpty(monthlyBillList))
            {
                return monthlyBillList;
            }
            
            // 如果是已支付或者部分支付，则不能勾销
            for (MonthlyBillDTO monthBill : monthlyBillList)
            {
                String billStatus1 = monthBill.getBillStatus();
                if (null != billStatus1 && !BillStatusEnum.BIST3.getCode().equals(billStatus1))
                {
                    monthBill.setId(null);
                }
            }
            
            // 如果已生成退租账单，则不让勾销
            PreOffrentBill preOffrentBill = preOffrentBillReadMapper.queryByContractId(Integer.parseInt(contractId));
            if (null != preOffrentBill)
            {
                for (MonthlyBillDTO monthBill : monthlyBillList)
                {
                    monthBill.setId(null);
                }
            }
            return monthlyBillList;
        }
        
        // 查询出所有，删除态时可能被勾销成0造成的，要具体判断是否要查询出
        List<MonthlyBillDTO> monthlyBillList = monthlyBillReadMapper.getDTOList(queryUtil);
        
        if (CollectionUtils.isEmpty(monthlyBillList))
        {
            return monthlyBillList;
        }
        
        return monthlyBillList;
    }    

    @Override
    public MonthlyBillDTO getDTO(Integer monthlyBillId) {
        MonthlyBillDTO monthlyBillDTO = monthlyBillReadMapper.selectDTOByPrimaryKey(monthlyBillId);
        return monthlyBillDTO;
    }

    @Override
    public void createEleMonthlyBill() {
        //TOOD by Junny
       // List<ContractMonthFeeDTO> contractEleList = contractReadMapper.queryContractEle(2, null);
        List<ContractMonthFeeDTO> contractEleList = null;
        String billMonth = DateUtil.getInstence().convertYM(new Date());
        //上月月末 -1
        Date start = DateUtils.addDays(DateUtil.getInstence().getLastDayOfLastMonth((new Date())), -1);
        //月末-2
        Date end = DateUtils.addDays(DateUtil.getInstence().getLastDayOfMonth((new Date())), -2);

        //首付款 且入住在上月月末-2 之前
        List<Integer> roomIds = new ArrayList<>();
        List<ContractMonthFeeDTO> regularBill = new ArrayList<ContractMonthFeeDTO>();
        for (ContractMonthFeeDTO dto : contractEleList) {
            if (dto.getBillTerm() != 1) {
                int i = DateUtil.compareTime(start, end);
                if (i == 1) {
                    roomIds.add(dto.getRoomId());
                    regularBill.add(new ContractMonthFeeDTO(dto.getId(), dto.getRoomId(), dto.getElectricPrice(),
                            dto.getWaterPrice(), null, null));
                } else {
                    dto.setBillTerm(1);
                }

            }
        }
        for (ContractMonthFeeDTO dto : contractEleList) {
            if (dto.getBillTerm() == 1) {
                Date inDate = dto.getInDate();
                //入住第一天电量单独算
                Date inFirstDate = DateUtils.addDays(inDate, 1);
                HashMap<String, Object> conMap = new HashMap<String, Object>();
                CheckFeeListDTO checkFeeListDTO = checkFeeListReadMapper.selectConsumptionEnd(dto.getId(), BillTypeEnum.CTBI2.getCode());
                //取出电表上的读数
                Double consumptionEnd = checkFeeListDTO.getConsumptionEnd();
                //取出入住第一天的电量
                Double firstDayConsumption = meterDataReadMapper.queryInDayConsumption(dto.getRoomId(), dto.getInDate()).getTotalTo();
                Double signDayConsumption = firstDayConsumption - consumptionEnd;
                Integer[] ids = {dto.getRoomId()};
                HashMap<String, Object> parmMap = new HashMap<String, Object>();
                parmMap.put("ids", ids);
                parmMap.put("start", inFirstDate);
                parmMap.put("end", end);
                parmMap.put("meterType", 1);
                List<MeterConsumptionDataDTO> roomList = meterDataReadMapper.queryRoomAndConsumption(parmMap);
                if (roomList.size() > 0) {
                    MeterConsumptionDataDTO meterConsumptionData = roomList.get(0);
                    Double totalConsumption = meterConsumptionData.getConsumption() + signDayConsumption;
                    Double elePrice = LandSeaUtil.get2Double(totalConsumption * (dto.getElectricPrice()));
                    //存入账单表里面
                    MonthlyBill record = new MonthlyBill();
                    //MonthlyBill monthlyBill = new MonthlyBill(dto.getId(), dto.getRoomId(), BillStatusEnum.BIST3.getCode(), BillTypeEnum.CTBI2.getCode(), totalConsumption, LandSeaUtil.get2Double(elePrice), inDate, end, ConstantChar.two_num);
                    record.setContractId(dto.getId());
                    record.setRoomId(dto.getRoomId());
                    record.setConsumption(totalConsumption);
                    record.setBillPrice(elePrice);
                    record.setStatus(BillStatusEnum.BIST3.getCode());
                    record.setStartTime(start);
                    record.setEndTime(end);
                    record.setExpenseType(BillTypeEnum.CTBI2.getCode());
                    record.setInputType(ConstantChar.two_num);
                    record.setBillMonth(billMonth);
                    monthlyBillWriteMapper.insertSelective(record);
                }
            }
            //else{
            //
            //
            //			}
        }
        //处理正常周期的电费账单
        if (regularBill.size() > 0) {
            HashMap<String, Object> parmMap = new HashMap<String, Object>();
            parmMap.put("ids", roomIds);
            parmMap.put("start", start);
            parmMap.put("end", end);
            parmMap.put("meterType", 1);
            List<MeterConsumptionDataDTO> roomList = meterDataReadMapper.queryRoomAndConsumption(parmMap);

            for (ContractMonthFeeDTO ctrInfo : regularBill) {
                MeterConsumptionDataDTO mdataDto = LandSeaUtil.queryUsedByRoomId(ctrInfo.getRoomId(), roomList);
                if (mdataDto != null) {
                    Double totalConsumption = mdataDto.getConsumption();
                    Double elePrice = totalConsumption * (ctrInfo.getElectricPrice());
                    //存入账单表里面
                    MonthlyBill record = new MonthlyBill();
                    record.setContractId(ctrInfo.getId());
                    record.setRoomId(ctrInfo.getRoomId());
                    record.setConsumption(totalConsumption);
                    record.setBillPrice(elePrice);
                    record.setStatus(BillStatusEnum.BIST3.getCode());
                    record.setStartTime(start);
                    record.setEndTime(end);
                    record.setExpenseType(BillTypeEnum.CTBI2.getCode());
                    record.setInputType(ConstantChar.two_num);
                    record.setBillMonth(billMonth);
                    monthlyBillWriteMapper.insertSelective(record);
                }

            }
        }
    }


    private void buildMonthlyRecordFromBalance(List<BalanceSheetRecord> balanceSheetRecords, Integer contractId, List<MonthlyBillDTO> resultList)
    {
        MonthlyBillDTO monthlyBillBalance = null;
        for (BalanceSheetRecord balanceSheetRecord : balanceSheetRecords)
        {
            monthlyBillBalance = new MonthlyBillDTO();
            monthlyBillBalance.setBillMonth(balanceSheetRecord.getBillMonth());
            monthlyBillBalance.setBillNo(balanceSheetRecord.getBillNo());
            monthlyBillBalance.setBillPrice(balanceSheetRecord.getReceivableMoney());
            monthlyBillBalance.setComment(balanceSheetRecord.getMark());
            monthlyBillBalance.setContractId(contractId);
            monthlyBillBalance.setEndTime(balanceSheetRecord.getEndTime());
            monthlyBillBalance.setExpenseType(balanceSheetRecord.getExpenditureCode());
            monthlyBillBalance.setExpenseTypeDesc(balanceSheetRecord.getExpenditure());
            monthlyBillBalance.setLastModifiedBy(balanceSheetRecord.getLastModifiedBy());
            monthlyBillBalance.setRoomId(balanceSheetRecord.getRoomId());
            monthlyBillBalance.setStartTime(balanceSheetRecord.getStartTime());
            monthlyBillBalance.setStatus(balanceSheetRecord.getBillStatus());
            
            resultList.add(monthlyBillBalance);
        }
    }
    
    private Map<String,List<Integer>> getMaxBalanceIdMap(List<MonthlyBillBalanceRecord> list)
    {
        Map<String,List<Integer>> balaceIdMap = new HashMap<String,List<Integer>>();
        for (MonthlyBillBalanceRecord monthlyBillBalanceRecord : list)
        {
            List<Integer> balaceIdList = balaceIdMap.get(String.valueOf(monthlyBillBalanceRecord.getId()));
            if (null == balaceIdList)
            {
                balaceIdList = new ArrayList<Integer>();
                balaceIdMap.put(String.valueOf(monthlyBillBalanceRecord.getId()), balaceIdList);
            }
            
            if (!balaceIdList.contains(monthlyBillBalanceRecord.getBsId()))
            {
                balaceIdList.add(monthlyBillBalanceRecord.getBsId());
            }
        }
        
        return balaceIdMap;
    }
    
    /**
     * 
     * [简要描述]：判断IntList的最大值</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-09-26)</br>
     *
     * @param idList
     * @param id
     * @return
     *
     */
    private boolean isMaxId(List<Integer> idList, Integer id)
    {
        Integer maxInt = Collections.max(idList);
        return id.intValue() == maxInt.intValue();
    }

}




